#include <regex.h>
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
#include <wininet.h>

char* ReadFileAll(wchar_t* fname) {
  HANDLE hFile = CreateFileW(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  LARGE_INTEGER fileSize;
  GetFileSizeEx(hFile, &fileSize);
  DWORD len = fileSize.QuadPart;
  char* str = malloc(len + 1);
  DWORD dwRead;
  ReadFile(hFile, str, len, &dwRead, NULL);
  CloseHandle(hFile);
  str[len] = '\0';
  return str;
}

char* hash_sha1(char* str, int islen) {
  HCRYPTPROV hProv = 0;
  HCRYPTHASH hHash = 0;
  CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
  if (!islen) islen = strlen(str);
  CryptHashData(hHash, str, islen, 0);
  DWORD outlen = 20;
  BYTE outhash[20] = {0};
  CryptGetHashParam(hHash, HP_HASHVAL, outhash, &outlen, 0);
  CryptDestroyHash(hHash);
  CryptReleaseContext(hProv, 0);
  char* strhash = malloc(41);
  char hex[] = "0123456789abcdef";
  for (int i = 0; i < 20; i++) {
    strhash[i * 2] = hex[outhash[i] >> 4];
    strhash[i * 2 + 1] = hex[outhash[i] & 0xf];
  }
  strhash[40] = '\0';
  return strhash;
}

char* getGitsha1(char* str) {
  int islen = strlen(str);
  int i = 0;
  for (int l = islen; l; l = l / 10, i++)
    ;
  int gslen = islen + 6 + i;
  char* gitstr = malloc(gslen + 1);
  sprintf(gitstr, "blob %d0%s", islen, str);
  gitstr[5 + i] = '\0';
  char* outstr = hash_sha1(gitstr, gslen);
  free(gitstr);
  return outstr;
}

char* getDate(char* str) {
  regex_t regex;
  regcomp(&regex, "Last updated: ([0-9\\-]+)", REG_EXTENDED);
  regmatch_t match[2] = {0};
  int res = regexec(&regex, str, 2, match, 0);
  if (res) return NULL;
  char* out = malloc(11);
  strncpy(out, str + match[1].rm_so, 10);
  out[10] = '\0';
  regfree(&regex);
  return out;
}

wchar_t* getHostInfo(char* str) {
  char* date = getDate(str);
  if (!date) {
    free(date);
    return L"未知";
  }
  char* sha1 = getGitsha1(str);
  wchar_t* out = malloc(30);
  swprintf(out, 30, L"%S %.7S", date, sha1);
  free(date);
  free(sha1);
  return out;
}

DWORD HttpHeaderNum(HINTERNET hReq, DWORD type) {
  DWORD num = 0;
  DWORD numlen = 4;
  HttpQueryInfoA(hReq, type | HTTP_QUERY_FLAG_NUMBER, &num, &numlen, NULL);
  return num;
}

char* HttpReadAll(HINTERNET hReq, DWORD contlen) {
  char* cont = malloc(contlen + 1);
  DWORD _;
  InternetReadFile(hReq, cont, contlen, &_);
  cont[contlen] = '\0';
  return cont;
}

void SaveTextFile(wchar_t* fname, char* data) {
  HANDLE hOut = CreateFileW(fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL, NULL);
  DWORD n;
  WriteFile(hOut, data, strlen(data), &n, NULL);
  CloseHandle(hOut);
}